;; XForth, a minimal Forth system for Intel x86-32 ELF executables
format elf executable 3
entry _start
include 'symbols.inc'
  include '/lib/live/mount/persistence/sdb2/trans/fasm/include/proc32.inc'
  include '/lib/live/mount/persistence/sdb2/trans/fasm/include/print.inc'

;; Public domain disclaimer:
;; I release this work into the public domain.
;; In case this isn't possible, I grant you the right to do whatever you want with this code.

  ;; Entrypoints are addresses referencing some code. They can reference native and directly
  ;; runnable code or a interpretable word.  In the case of directly runnable code, they are meant
  ;; to internal interpreter use. They can be call-able (you start its execution with a `call`
  ;; instruction, they return to your code with a 'ret' instruction) or jmp-able (you start it
  ;; with a 'jmp' instruction, they will continue to execute internal interpreter's code).

  ;; EBP holds the return stack top. ESP holds the data stack top.

_pushrst:                       ;Native call-able entrypoint to push ESI onto return stack
  lea ebp, [ebp-4]
  mov [ebp], esi
  ret
_poprst:                        ;Native call-able entrypoint to pop the return stack into ESI
  mov esi, [ebp]
  lea ebp, [ebp+4]
  ret

  ;; Words are (potentially) user-accessible sets of instructions. Every word has a entrypoint and
  ;; a definition (its contents). They can be run by the interpreter, can call or be called by
  ;; other words through the interpreter (which supports the word's code controlling the return
  ;; stack for proper operation) and can be referenced at a dictionary.

  ;; Codewords are special entrypoints used as a pointer in the beggining of the definition of
  ;; every word. They implement the specific interpreter code needed to execute that word.

_enter_native:                  ;Codeword for native words: words made of native machine code
  jmp esi
_leave_routine:                 ;Word to end a virtual routine
  dd _enter_native
_end_caller:                    ;Jmp-able entrypoint to end the caller routine
  call _poprst
_next_routine:                  ;Jmp-able entrypoint to end the current native routine
  call _poprst
  add esi, 4
_enter_routine:                 ;Codeword for virtual words: words made of other words entrypoints
  call _pushrst
  lodsd
  mov esi, eax
_next:                          ;Entrypoint to jump into the next word's codeword
  lodsd
  jmp eax

_halt:
  dd _enter_native
  mov eax, sys_exit
  mov ebx, 0
  int 80h

  ;; `_literal` word gets the value that should be the next word to be run in the current routine
  ;; and pushes this value at the data stack, skipping its execution.

_literal:
  dd _enter_native
  add dword [ebp], 4            ;Return stack top points at the next word to be run
  mov eax, [ebp]
  push dword [eax]
  jmp _next_routine

  flag_immediate = 0x80
  flag_hidden = 0x40

  include 'primitives.asm'

_start:
  cld
  mov ebp, esp
  sub esp, 2*1024*1024          ;Return stack size: 2MB
  mov [data_stack_bottom], esp
  mov [return_stack_bottom], ebp
  mov esi, _forth_boot
  jmp _next

  ;; Faux word to bootstrap the interpreter:

_forth_boot:
  dd _enter_routine
  dd main
  dd _halt

main:
  dd _enter_routine
  ;; Empty by now
  dd _leave_routine

segment writeable readable
  read:
    .buffer rb 4096
    .cursor rw 1
    .top    rw 1
  word_buffer:  rb 32
  reg_buffer registers
  return_stack_bottom:  rd 1
  data_stack_bottom:    rd 1
  compiling_state:      rb 1
